/*global pi */
pi.mod.define('pi.scene', function (pi) {
	"use strict";

	var module = {}, i, handle2obj = {}, name2obj = {},
		skyBox = {},
		vcalls = [
			["s3d_create", pi.vcall.TYPE_INT, [pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT]],
			["s3d_copy", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT]],
			["s3d_destroy", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT]],
			["s3d_update_scene", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT]],
			["s3d_create_obj", pi.vcall.TYPE_INT, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT]],
			["s3d_destroy_obj", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT]],
			["s3d_get_attachment", pi.vcall.TYPE_INT, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT]],
			["s3d_set_attachment", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_INT]],
			["s3d_set_pos", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT]],
			["s3d_get_pos", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_POINTER]],
			["s3d_set_scale", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT]],
			["s3d_get_scale", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_POINTER]],
			["s3d_set_orient", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT]],
			["s3d_get_orient", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_POINTER]],
			["s3d_get_world_mat", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_POINTER]],
			["s3d_look_at", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT]],
			["s3d_update_camera", pi.vcall.TYPE_INT, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT]],
			["s3d_create_camera", pi.vcall.TYPE_INT, [pi.vcall.TYPE_INT]],
			["s3d_set_camera_projection", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT]],
			["s3d_set_mask", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_INT]],
			["s3d_from_camera_to_world", pi.vcall.TYPE_VOID, [pi.vcall.TYPE_INT, pi.vcall.TYPE_INT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_FLOAT, pi.vcall.TYPE_POINTER]]
		],
		MASK_VISIBLE  = 0x00000001, // 可见物体
		MASK_AREA_BOX = 0x00000002, // 场景调度碰撞体
		MASK_AREA_FRAME = 0x00000004, // 场景调度区域的线框
		MASK_TERRAIN_MESH = 0x00000008, // 地块 mesh
		MASK_STAND_ON = 0x00000010, // 可站立物体
		MASK_OBSTACLE = 0x00000020, // 寻路障碍物
		MASK_ALL = -1; // 默认不过任何过滤的掩码

	module.MASK_OBSTACLE = MASK_OBSTACLE;
	module.MASK_VISIBLE = MASK_VISIBLE;
	module.MASK_USER = 0x00010000; // 应用层可以开始使用的掩码

	// 注册所有 vcall 函数句柄
	pi.vcall.makeVCall("s3d.dll", module, vcalls);

	/** 创建场景 */
	module.create = function (min, max, name) {
		var scene = {}, cameras = [], objs = [],
			posArr = pi.lang.createF32Array(3),
			scaleArr = pi.lang.createF32Array(3),
			orientArr = pi.lang.createF32Array(4),
			worldMat = pi.lang.createF32Array(16),
			sh = vcalls.s3d_create(min.x, min.y, min.z, max.x, max.y, max.z),
			snapshoots = {}, // 场景快照
			cameraQuery = pi.scene.query.createCameraQuery(scene),
			terrainHeightQuery = function (pos) {
				var i, dist, minDist,
					rayQuery = pi.scene.query.createRayQuery(scene, MASK_STAND_ON),
					lst = rayQuery.doQuery(pos, {x: pos.x, y: pos.y - 10000, z: pos.z}, true);

				if (lst.length === 0) {
					return undefined;
				}

				for (i = 0; i < lst.length; i++) {
					dist = rayQuery.getDist(lst[i]).near;
					if (minDist === undefined || dist < minDist) {
						minDist = dist;
					}
				}

				return pos.y - dist;
			},
			addSpaceMethods = function (so) {
				var soh = so.handle,
					mov = {};

				/** 设置场景物件坐标 */
				so.setPos = function (pos) {
					vcalls.s3d_set_pos(sh, soh, pos.x, pos.y, pos.z);
				};

				/** 获取坐标 */
				so.getPos = function () {
					vcalls.s3d_get_pos(sh, soh, posArr);
					return {
						x: posArr[0],
						y: posArr[1],
						z: posArr[2]
					};
				};

				/** 设置场景物件缩放 */
				so.setScale = function (scale) {
					vcalls.s3d_set_scale(sh, soh, scale.x, scale.y, scale.z);
				};

				/** 获取坐标 */
				so.getScale = function () {
					vcalls.s3d_get_scale(sh, soh, scaleArr);
					return {
						x: scaleArr[0],
						y: scaleArr[1],
						z: scaleArr[2]
					};
				};

				/** 设置场景物件的方向 */
				so.setOrient = function (orient) {
					vcalls.s3d_set_orient(sh, soh, orient.w, orient.x, orient.y, orient.z);
				};

				/** 获取方向 */
				so.getOrient = function () {
					vcalls.s3d_get_orient(sh, soh, orientArr);
					return {
						w: orientArr[0],
						x: orientArr[1],
						y: orientArr[2],
						z: orientArr[3]
					};
				};

				/** 获取世界变换矩阵 */
				so.getWorldMat = function () {
					vcalls.s3d_get_world_mat(sh, soh, worldMat);
					return worldMat;
				};

				/** 旋转场景物体使之指向指定点 */
				so.lookAt = function (pos, fixY) {
					fixY = fixY || true;
					vcalls.s3d_look_at(sh, soh, pos.x, pos.y, pos.z, 0, fixY ? 1 : 0, 0);
				};

				/** 调整物体高度到地表 */
				so.onGround = function (offset) {
					var pos = so.getPos(),
						off = offset || 0,
						y = terrainHeightQuery({x: pos.x, y: pos.y + 5, z: pos.z});

					if (y !== undefined) {
						pos.y = y + off;
					}
					so.setPos(pos);
				};

				/** 按指定速度和路径移动 */
				so.movePath = function (path, speed, onGround) {
					var i, d, t, totalTime, pt1, pt2;

					// 根据高度精度插值路径点
					if (onGround) {
						path = pi.scene.movement.interpPath(path, terrainHeightQuery, 10);
					}

					// 计算每段路径的运动时间
					totalTime = 0;
					for (i = 0; i < path.length - 1; i++) {
						pt1 = path[i];
						pt2 = path[(i + 1) % path.length];
						d = pi.math.vec3.distance(pt1, pt2);
						t = d / speed;
						totalTime += t;
						pt1.time = t;
					}

					path[path.length - 1].time = 0;

					// 创建运动对象
					so.stopMove();
					mov.moveTo = pi.scene.movement.create(so, pi.scene.movement.createPathMovFun(path, true,
										onGround ? terrainHeightQuery : undefined));

					return totalTime;
				};

				/** 停止移动 */
				so.stopMove = function () {
					pi.scene.movement.del(mov.moveTo);
				};

				/** 按指定速度旋转向给定目标 */
				so.turnTo = function (aimPos, xzOnly, time) {
					var qTo, qFrom = so.getOrient(), arcDist, pos = so.getPos();

					////---- 暂时要反一下，现在不确定是模型反了还是计算反了
					aimPos = {x: pos.x * 2 - aimPos.x, y: pos.y * 2 - aimPos.y, z: pos.z * 2 - aimPos.z};
					so.lookAt({x: aimPos.x, y: (xzOnly ? so.getPos().y : aimPos.y), z: aimPos.z}, true);
					qTo = so.getOrient();
					so.setOrient(qFrom);

					pi.scene.movement.del(mov.turnTo);
					mov.turnTo = pi.scene.movement.create(so, pi.scene.movement.createRotationFun(qFrom, qTo, time, true));
				};

				/** 按给定参数播放动画序列 */
				so.playAni = function (aniParams) {
					so.stopAni();
					mov.playAni = pi.scene.movement.create(so, pi.scene.movement.createAniShiftFun(aniParams));
				};

				/** 停止动画播放 */
				so.stopAni = function (ani) {
					pi.scene.movement.del(mov.playAni);
					if (ani !== undefined) {
						so.setAni(ani);
					}
				};
			};

		scene.showAABB = false; // 默认不显示 aabb
		scene.handle = sh; // 场景句柄
		scene.showOctree = false; // 是否显示场景树分割
		scene.name = name || "noname"; // 场景名称
		scene.renderMask = MASK_VISIBLE; // 渲染掩码，决定哪些东西被显式

		/** 创建场景物体
			ro: 渲染对象，可以是一个 mesh、billboard、particleSystem 等
			返回：场景对象
		 */
		scene.createObj = function () {
			var so = {},
				soh = vcalls.s3d_create_obj(sh, 0),
				visible = false,
				name,
				mask = 0;

			so.handle = soh;
			so.ready = false;
			so.sceneHandle = sh;

			/** 设置物体名称 */
			so.setName = function (objName) {
				if (name2obj[objName] !== undefined) {
					throw "scene object name conflict! name=" + objName;
				}

				if (name !== undefined) {
					name2obj[name] = undefined;
				}

				if (objName === undefined) {
					return;
				}

				name = objName;
				name2obj[objName] = so;
			};

			/** 获取物体名称 */
			so.getName = function () {
				return name;
			};

			/** 场景物件是否可见 */
			so.isVisible = function () {
				return visible;
			};

			/** 设置场景物件是否可见 */
			so.setVisible = function (v) {
				if (visible === v) {
					return;
				}

				visible = v;
				so.setMask(mask);
			};

			/** 附加 mesh */
			so.attach = function (ro) {
				so.ro = ro;
				vcalls.s3d_set_attachment(sh, soh, ro.handle);
				return so;
			};

			/** 移除 mesh */
			so.dettach = function () {
				so.ro = undefined;
				vcalls.s3d_set_attachment(sh, soh, 0);
				return so;
			};

			/** 设置掩码 */
			so.setMask = function (msk) {
				mask = visible ? (msk | MASK_VISIBLE) : (msk & (~MASK_VISIBLE));
				vcalls.s3d_set_mask(sh, soh, mask);
			};

			/** 获取掩码 */
			so.getMask = function () {
				return mask;
			};

			addSpaceMethods(so);
			objs.push(so);

			// 建立场景物件 c 句柄到 js 对象的映射关系
			handle2obj[soh] = so;

			return so;
		};

		/** 根据名字获取场景物件 */
		scene.getByName = function (objName) {
			return name2obj[objName];
		};

		/**创建一个扇形*/
		scene.createSector = function (radius, radian, color, num) {
			var so = scene.createObj();
			pi.scene.creators.createSector(so, radius, radian, color, num);
			return so;
		};

		/**创建一个圆锥*/
		scene.createCone = function (radius, height, color, num) {
			var so = scene.createObj();
			pi.scene.creators.createCone(so, radius, height, color, num);
			return so;
		};

		/**创建一个圆柱*/
		scene.createCylinder = function (radius, height, color, num) {
			var so = scene.createObj();
			pi.scene.creators.createCylinder(so, radius, height, color, num);
			return so;
		};


		/** 创建一个立方体 */
		scene.createCube = function (color) {
			var so = scene.createObj();
			pi.scene.creators.createCube(so, false, color);
			return so;
		};

		/** 创建一个立方体线框 */
		scene.createCubeframe = function (color) {
			var so = scene.createObj();
			pi.scene.creators.createCube(so, true, color);
			return so;
		};

		/** 创建一个线对象 */
		scene.createLine = function (startPt, endPt, color) {
			var so = scene.createObj();
			pi.scene.creators.createLine(so, startPt, endPt, color);
			return so;
		};

		/** 创建一个模型 */
		scene.createEntity = function (cfg) {
			var so = scene.createObj();
			pi.scene.creators.createEntity(so, cfg);
			return so;
		};

		/** 创建摄像机 */
		scene.createCamera = function () {
			var cam = {},
				ch = vcalls.s3d_create_camera(sh),
				rtWidth = 800,
				rtHeight = 600,
				tmpVec3 = pi.lang.createF32Array(3),
				resize;

			cam.handle = ch;

			/** 摄像机的顶的朝向 */
			cam.up = {
				x: 0,
				y: 1,
				z: 0
			};

			/** 根据屏幕点击位置计算查询射线 */
			cam.getRay = function (w, h) {
				var nearPt,
					midPt,
					dir = {};

				vcalls.s3d_from_camera_to_world(sh, ch, w * 2 - 1, 1 - h * 2, -1, tmpVec3);
				nearPt = {x: tmpVec3[0], y: tmpVec3[1], z: tmpVec3[2]};
				vcalls.s3d_from_camera_to_world(sh, ch, w * 2 - 1, 1 - h * 2, 1, tmpVec3);
				midPt = {x: tmpVec3[0], y: tmpVec3[1], z: tmpVec3[2]};
				return pi.scene.ray.create(nearPt, midPt);
			};

			/** 重置窗口大小 */
			cam.resize = function (width, height) {
				rtWidth = width;
				rtHeight = height;
				resize();
			};

			/** 获取平截头体的 c 句柄 */
			cam.getFrustumHandle = function () {
				return vcalls.s3d_get_attachment(sh, ch);
			};

			/** 设置投影参数 */
			cam.setProjection = function (fovRad, ratio, disNear, disFar) {
				vcalls.s3d_set_camera_projection(sh, ch, fovRad, ratio, disNear, disFar);
				resize = function () {
					vcalls.s3d_set_camera_projection(sh, ch, fovRad, rtWidth / rtHeight, disNear, disFar);
				};
			};

			addSpaceMethods(cam);
			cameras.push(cam);

			return cam;
		};

		/** 销毁一个摄像机 */
		scene.destroyCamera = function (cam) {
			var i;
			i = cameras.indexOf(cam);
			cameras.splice(i, 1);
			vcalls.s3d_destroy_obj(sh, cam.handle);
		};

		/** 销毁一个场景对象
			so: 场景对象
		*/
		scene.destroyObj = function (so) {
			var objName = so.getName();

			vcalls.s3d_destroy_obj(sh, so.handle);
			objs.splice(objs.indexOf(so), 1);
			if (objName !== undefined) {
				name2obj[objName] = undefined;
			}
			handle2obj[so.handle] = undefined;
		};

		/** 根据场景对象句柄获取 */
		scene.getObjByHandle = function (objHandle) {
			return handle2obj[objHandle];
		};

		/** 重置渲染目标尺寸 */
		scene.resize = function (width, height) {
			var i;
			for (i = 0; i < cameras.length; i++) {
				cameras[i].resize(width, height);
			}
		};

		/** 更新整个场景 */
		scene.update = function (timeElapsed) {
			var i, j, obj, pos;

			for (i = 0; i < objs.length; i++) {
				// 调整更新顺序，如果 a bindTo b，则需要先更新 b 再更新 a
				obj = objs[i];
				if (obj.bindTo !== undefined) {
					j = objs.indexOf(obj.bindTo);
					if (j > i) {
						objs.splice(i, 1);
						objs.push(obj);
						i--;
						continue;
					}
				}

				if (pi.lang.isFunction(obj.update)) {
					if (obj.loaded) {
						obj.update(timeElapsed);
					}
				}
			}

			vcalls.s3d_update_scene(sh);
			for (i = 0; i < cameras.length; i++) {
				vcalls.s3d_update_camera(sh, cameras[i].handle);
			}
		};

		/** 设置天空盒 */
		scene.setSkyBox = function (texs) {
			skyBox.loaded = false;
			var h = pi.render.t3d.createSkybox();
			skyBox.box = pi.res.create(h, undefined, function (handle, info) {
				pi.log("释放天空盒句柄");
				pi.render.t3d.destroySkyBox(handle);
			});

			pi.res.loads(texs, function (arr) {
				// 有一个加载错误
				if (arr.error) {
					pi.log("------------ loads skybox texture error, reason = " + arr.reason);
				} else {
					skyBox.texs = arr;
					skyBox.loaded = true;
				}
			});
		};

		/** 设置地表 */
		scene.createTerrain = function (cfg) {
			var i, terrain = {}, cfgArr = [], scale = cfg.scale;

			terrain.loaded = false;
			cfgArr[0] = [cfg.data, pi.res.FILE];
			for (i = 0; i < cfg.tex.length; i++) {
				cfgArr[i + 1] = [cfg.tex[i], pi.res.TEX];
			}

			// 载入真正的地形资源，并创建地形
			pi.res.loads(cfgArr, function (arr) {
				var i, h, pos;
				if (arr.error) {
					for (i = 0; i < arr.length; i += 1) {
						if (arr[i].reason) {
							pi.log("i = " + i + ", arr[i].reason = " + arr[i].reason);
						}
					}
					return;
				}

				terrain.tex1 = arr[1];
				terrain.countTex1 = cfg.count1;
				terrain.tex2 = arr[2];
				terrain.countTex2 = cfg.count2;

				terrain.alpha = arr[3];
				terrain.countTexArr = cfg.countArray;
				terrain.extArray = arr.slice(4);
				h = pi.render.t3d.createTerrain(cfg.width, cfg.depth, arr[0].handle, scale.x, scale.y, scale.z);

				terrain.mat = pi.math.mat4.create();
				pos = pi.math.vec3.create(cfg.pos.x, cfg.pos.y, cfg.pos.z);
				pi.math.mat4.translate(terrain.mat, pos);

				terrain.data = pi.res.create(h, undefined, function (handle, info) {
					pi.log("释放地形句柄");
					pi.render.t3d.destroyTerrain(handle);
				});

				terrain.loaded = true;
			});

			return terrain;
		};

		/** 销毁场景内部资源，不要直接调用该方法，而应该调用 module.destroy */
		scene.destroyInternal = function () {
			var i;
			for (i = 0; i < cameras.length; i++) {
				scene.destroyCamera(cameras[i]);
			}
			pi.lang.free(posArr);
			pi.lang.free(scaleArr);
			pi.lang.free(orientArr);
		};

		/** 渲染场景
			cam: 摄像机
		 */
		scene.render = function (cam, buf) {
			var i, obj, objList, numBones, boneMats, terrain;

			// 先设置摄像机
			pi.render.run.setCamera(buf, cam.getPos(), cam.up, cam.getFrustumHandle());

			// 做剪裁查询
			objList = cameraQuery.doQuery(cam, scene.renderMask);

			// 渲染天空盒
			if (skyBox.loaded) {
				pi.render.run.drawSkybox(buf, skyBox.box, skyBox.texs[0], skyBox.texs[1], skyBox.texs[2], skyBox.texs[3], skyBox.texs[4], skyBox.texs[5]);
			}

			// 渲染地表
			for (i = 0; i < scene.loadedTerrain.length; i++) {
				terrain = scene.loadedTerrain[i].terrain;
				if (terrain !== undefined && terrain.loaded) {
					pi.render.run.drawTerrain(buf, terrain.data, terrain.mat, terrain.tex1, terrain.countTex1,
						terrain.tex2, terrain.countTex2,
						terrain.alpha, terrain.extArray,
						terrain.countTexArr);
				}
			}

			// 渲染查询到的场景物体
			for (i = 0; i < objList.length; i++) {
				obj = objList[i];
				if (obj.loaded) {
					numBones = obj.ani === undefined ? 0 : obj.ani.numBones;
					boneMats = obj.ani === undefined ? undefined : obj.getBoneMats();
					pi.render.run.drawMesh(buf, obj.ro, obj.tex, numBones, boneMats, obj.getPos(), obj.translucent ? 0 : 1, obj.getWorldMat(), scene.showAABB);
				}
			}
		};

		/** 加载指定 terrain */
		scene.loadTerrain = function (terrain) {
			pi.log("load terrain");

			var cfg = terrain.cfg;
			terrain.terrain = scene.createTerrain(cfg);
			terrain.loaded = true;
			terrain.toBeUnload = false;
			scene.loadedTerrain.push(terrain);
		};

		/** 卸载指定 terrain */
		scene.unloadTerrain = function (terrain) {
			pi.log("unload terrain");
			terrain.terrain = undefined;
			terrain.loaded = false;
			terrain.toBeUnload = false;
			scene.loadedTerrain.splice(scene.loadedTerrain.indexOf(terrain), 1);
		};

		/** 加载指定 area */
		scene.loadArea = function (area) {
			pi.log("load area");
			var i, obj, cfg;

			// objects
			area.objs = [];
			for (i = 0; i < area.cfg.objs.length; i++) {
				cfg = area.cfg.objs[i];
				obj = scene.createEntity(cfg.model);
				obj.setVisible(true);
				obj.setName(cfg.name);
				if (cfg.pos !== undefined) {
					obj.setPos(cfg.pos);
				}
				if (cfg.scale !== undefined) {
					obj.setScale(cfg.scale);
				}
				if (cfg.orient !== undefined) {
					obj.setOrient(cfg.orient);
				}
				if (cfg.ani !== undefined) {
					obj.setAni(cfg.ani);
				}
				if (cfg.bindTo !== undefined) {
					scene.getByName(cfg.bindTo.obj).bind(cfg.bindTo.boneId, obj);
				}
				area.objs.push(obj);
			}

			area.loaded = true;
			area.toBeUnload = false;
			scene.loadedAreas.push(area);
		};

		/** 卸载指定的 area */
		scene.unloadArea = function (area) {
			pi.log("unload area");
			var i;
			for (i = 0; i < area.objs.length; i++) {
				scene.destroyObj(area.objs[i]);
			}

			area.objs = undefined;
			area.loaded = false;
			area.toBeUnload = false;
			scene.loadedAreas.splice(scene.loadedAreas.indexOf(area), 1);
		};

		/** 调度地块 */
		scene.scheduleTerrain = function (cam) {
			var i, terrain, meshes, terrains = scene.terrains,
				loadedTerrain = scene.loadedTerrain;

			if (terrains === undefined || terrains.length === 0) {
				return;
			}

			for (i = 0; i < loadedTerrain.length; i++) {
				loadedTerrain[i].toBeUnload = true;
			}

			meshes = cameraQuery.doQuery(cam, MASK_TERRAIN_MESH);
			for (i = 0; i < meshes.length; i++) {
				terrain = meshes[i].terrain;
				if (!terrain.loaded) {
					scene.loadTerrain(terrain);
				} else if (terrain.toBeUnload) {
					terrain.toBeUnload = false;
				}
			}

			for (i = 0; i < loadedTerrain.length; i++) {
				terrain = loadedTerrain[i];
				if (terrain.toBeUnload) {
					scene.unloadTerrain(terrain);
					i--;
				}
			}
		};

		/** 加载指定的场景区域 */
		scene.scheduleArea = function (cam) {
			var i, area, boxes, areas = scene.areas,
				loadedAreas = scene.loadedAreas;

			// 没分区域的场景就算了
			if (areas === undefined || areas.length === 0) {
				return;
			}

			// 先标记已经载入的区域，方便后续清除
			for (i = 0; i < loadedAreas.length; i++) {
				loadedAreas[i].toBeUnload = true;
			}

			// 加载区域
			boxes = cameraQuery.doQuery(cam, MASK_AREA_BOX);
			for (i = 0; i < boxes.length; i++) {
				area = boxes[i].area;
				if (!area.loaded) {
					scene.loadArea(area);
				} else if (area.toBeUnload) {
					area.toBeUnload = false;
				}
			}

			// 卸载那些需要卸载的区域
			for (i = 0; i < loadedAreas.length; i++) {
				area = loadedAreas[i];
				if (area.toBeUnload) {
					scene.unloadArea(area);
					i--;
				}
			}
		};

		/** 创建地表高度查询器 */
		scene.createHeightQuery = function () {
			var query = pi.scene.query.createRayQuery(scene, MASK_STAND_ON);
			return function (ray) {
				var i, obj, dist, minDist, vec3, pos,
					lst = query.doQuery(ray.start, ray.end, true);

				if (lst.length === 0) {
					return undefined;
				}

				for (i = 0; i < lst.length; i++) {
					obj = lst[i];
					dist = query.getDist(obj).near;
					if (minDist === undefined || dist < minDist) {
						minDist = dist;
					}
				}

				return {pos: ray.getPtByDist(minDist), obj: obj};
			};
		};

		/** 记录当前场景快照 */
		scene.taskSnapshoot = function (snapName) {
			var h = snapshoots[snapName];
			if (h === undefined) {
				h = vcalls.s3d_create(min.x, min.y, min.z, max.x, max.y, max.z);
			}
			vcalls.s3d_copy(h, sh);
			snapshoots[snapName] = h;
		};

		/** 销毁场景快照 */
		scene.destroySnapshoot = function (snapName) {
			var h = snapshoots[snapName];
			if (h === undefined) {
				return;
			}

			vcalls.s3d_destroy(h);
			snapshoots[snapName] = undefined;
		};

		/** 切换场景快照 */
		scene.setSnapshoot = function (snapName) {
			if (snapName === undefined && snapshoots.ORIGINAL_SCENE !== undefined) {
				sh = snapshoots.ORIGINAL_SCENE;
				snapshoots.ORIGINAL_SCENE = undefined;
			} else {
				if (snapshoots.ORIGINAL_SCENE === undefined) {
					snapshoots.ORIGINAL_SCENE = sh;
				}
				sh = snapshoots[snapName];
			}
		};

		/** 显示导航网络 */
		scene.setNavNetVisible = function (visible) {
			var i, j, pt, npt, navNet, lines = [];

			if (visible) {
				if (scene.nav.mesh === undefined) {
					navNet = scene.nav.getNavNet();
					for (i = 0; i < navNet.pts.length; i++) {
						for (j = i + 1; j < navNet.pts.length; j++) {
							if (navNet[i][j] !== undefined) {
								pt = navNet.pts[i];
								npt = navNet.pts[j];
								lines.push({start: pt, end: npt, color: {r: 0, g: 255, b: 0, a: 255}});
							}
						}
					}

					scene.nav.mesh = scene.createObj();
					pi.scene.creators.createLines(scene.nav.mesh, lines);
				}
			}

			if (scene.nav.mesh !== undefined) {
				scene.nav.mesh.setVisible(visible);
			}
		};

		return scene;
	};

	/** 销毁场景 */
	module.destroy = function (scene) {
		scene.destroyInternal();
		vcalls.s3d_destroy(scene.handle);
		scene.handle = 0;
	};

	/** 从配置文件加载场景 */
	module.load = function (cfg) {
		var i, areaBox, frameBox, area, aabb, terrain, obs, obsObj, nav,
			scene = module.create(cfg.aabb.min, cfg.aabb.max, cfg.name);

		scene.areas = [];
		scene.loadedAreas = [];
		scene.terrains = [];
		scene.loadedTerrain = [];

		if (cfg.terrains !== undefined) {
			// 为所有地形创建碰撞体
			for (i = 0; i < cfg.terrains.length; i++) {
				terrain = {};
				terrain.cfg = cfg.terrains[i];
				terrain.cfg.scale = terrain.cfg.scale || {x: 1, y: 1, z: 1};
				terrain.pos = cfg.pos;

				// 创建用于站立和调度的地表模型
				terrain.mesh = scene.createEntity({mesh: terrain.cfg.mesh});
				terrain.mesh.setPos(terrain.cfg.pos);
				terrain.mesh.setMask(MASK_TERRAIN_MESH | MASK_STAND_ON);
				terrain.mesh.setScale(terrain.cfg.scale);
				terrain.mesh.setVisible(false);
				terrain.mesh.terrain = terrain;

				scene.terrains[i] = terrain;
			}
		}

		if (cfg.areas !== undefined) {
			// 为所有的 area 创建碰撞体
			for (i = 0; i < cfg.areas.length; i++) {
				area = {};
				area.cfg = cfg.areas[i];
				aabb = area.cfg.aabb;
				areaBox = scene.createCube({r: 255, g: 255, b: 255, a: 64});
				areaBox.translucent = true;
				frameBox = scene.createCubeframe({r: 0, g: 255, b: 0, a: 255});
				frameBox.setPos({
					x: (aabb.max.x + aabb.min.x) / 2,
					y: (aabb.max.y + aabb.min.y) / 2,
					z: (aabb.max.z + aabb.min.z) / 2
				});
				areaBox.setPos({
					x: (aabb.max.x + aabb.min.x) / 2,
					y: (aabb.max.y + aabb.min.y) / 2,
					z: (aabb.max.z + aabb.min.z) / 2
				});
				frameBox.setScale({
					x: (aabb.max.x - aabb.min.x) / 2,
					y: (aabb.max.y - aabb.min.y) / 2,
					z: (aabb.max.z - aabb.min.z) / 2
				});
				areaBox.setScale({
					x: (aabb.max.x - aabb.min.x) / 2,
					y: (aabb.max.y - aabb.min.y) / 2,
					z: (aabb.max.z - aabb.min.z) / 2
				});
				frameBox.setVisible(false);
				areaBox.setVisible(false);
				frameBox.setMask(MASK_AREA_FRAME);
				areaBox.setMask(MASK_AREA_BOX);
				areaBox.area = area;
				areaBox.frameBox = frameBox;

				scene.areas[i] = area;
			}
		}

		// 创建导航信息
		scene.nav = pi.scene.nav.create(cfg.obstacles, pi.scene.query.createRayQuery(scene, MASK_OBSTACLE));

		// 构建所有障碍体
		obs = scene.nav.getAllObstacles();
		for (i = 0; i < obs.length; i++) {
			obsObj = scene.createObj();
			obsObj.setMask(MASK_OBSTACLE);
			obsObj.setVisible(true);
			pi.scene.creators.createObstacleEntity(obsObj, obs[i], {r: 128, g: 128, b: 128, a: 128});
			if (obs[i].pos !== undefined) {
				obsObj.setPos({x: obs[i].pos.x, y: 0, z: obs[i].pos.z});
			}
			obsObj.setScale({x: 0.99, y: 1, z: 0.99});
			obsObj.translucent = true;

			obsObj.obs = obs[i];
			obs[i].obj = obsObj;
		}

		return scene;
	};

	return module;
});
